# -*- coding: utf-8 -*-
#from IPython import embed; embed()
""" A widget for (phi, lamda, h) or (easting, northing, h) coordinates

The CoordWidget class implement a widget to display coordinates:  (lat, lon,
height) or (easting, northing height).
The widget has optional combo boxes both for degrees representation (D.DD or
D, M.MM or D, M, S.SS) and height (ellipsoidical or orthometric).
The appearance of the widget (phi, lamda, h) or (easting, northing, h) depends
on the Projection used.

    :Author:
      - 20111221-20120214 Roberto Vidmar

    :Revision:  $Revision: 52 $
                $Date: 2012-11-12 09:07:15 +0000 (Mon, 12 Nov 2012) $

    :Copyright: 2011-2012
                Nicola Creati <ncreati@inogs.it>
                Roberto Vidmar <rvidmar@inogs.it>

    :License: MIT/X11 License (see :download:`license.txt
                               <../../license.txt>`)
"""

import sys
from pyproj import __version__, Proj
from qtCompat import Qt, Signal, QtCore, QtGui

QCA = QtCore.QCoreApplication
from geodesy import DatumShift, Geoid
from degreesWidget import DegreesWidget
from heightWidget import HeightWidget
from projectedWidget import ProjectedWidget
from filePicker import FilePicker
from projDialog import (ProjDialog, DATUMSHIFT_KEYWORD, GEOIDGRIDS_KEYWORD,
  EXTRA_KEYWORDS)

class TinyButton(QtGui.QPushButton):
  """ A QPushButton with a size fitted to the button label
  """
  def __init__(self, label, parent):
    """ Create a new TinyButton instance.

    :param label: label to put on the tiny button
    :type label: string
    :param parent: parent widget
    :type parent: QtGui widget
    """
    super(TinyButton, self).__init__(label, parent)

    textWidth = self.fontMetrics().boundingRect(self.text()).width()
    self.setMaximumWidth(textWidth + 12)
    self.setFocusPolicy(Qt.NoFocus)

#===============================================================================
class CoordWidget(QtGui.QWidget):
  """ A widget for (phi, lamda, h) or (easting, northing, h) coordinates.
  """
  WGS84 = '+proj=latlong +datum=WGS84'
  changedSignal = Signal(object)
  fileChangedSignal = Signal(object)

  # Initial visualization Mode
  ModeD = 0
  ModeDM = 1
  ModeDMS = 2
  ModeFile = 3

  # Height
  RepEll = 0
  RepOrtho = 1

  # Stacked Widget: Plane or Geographic
  PlaneIndex = 0
  GeographicIndex = 1

  # Stacked Widget: Point or File
  PointIndex = 0
  FileIndex = 1

  def __init__(self, xyz=(0, 0, 0), labels=(
      u"\N{GREEK SMALL LETTER PHI}", u"\N{GREEK SMALL LETTER LAMDA}", u"H",
      u"E", u"N", u"Input File", u"Output File"),
      initMode=ModeD,
      repH=RepEll, ell2Ortho=None,
      name='', proj=WGS84, comboU='', comboH=True):
    """ Create a new instance of the widget.

      :param xyz: Tuple (x, y, z) where: x = Easting or longitude,
                  y = Northing or latitude, z = Ellipsoidical height
      :type xyz: tuple

      :param labels: labels to use for the different forms of the widget:
                     (φ, λ, H, E, N, InputFPCaption, OutputFPCaption)
      :type label: tuple
      :param initMode: Initial representation:
                       ModeD = D.DD or M.MM
                       ModeDM = D M.MM
                       ModeDMS = D M S.SS
                       ModeFile = File
      :type initMode: int
      :param repH: representation for height: RepEll = ell, RepOrtho = ortho
      :type repH: int
      :param ell2Ortho: offset to add to z to obtain orthometric height
      :type ell2Ortho: float
      :param name: optional name of this object
      :type name: string, unicode
      :param proj: Datum / Projection of xyz in PROJ.4 string form (default is
                   WGS84)
      :type proj: PROJ.4 string
      :param comboU: Add a combo box to select degrees representation
                     Default: True, Values: (False, True, 'File')
      :type comboU: bool or string
      :param comboH: Add a combo box to select height representation
      :type comboH: bool (default True)
  """
    super(CoordWidget, self).__init__()

    x, y, z = xyz
    self._ell2ortho = ell2Ortho
    self._hasComboU = comboU
    self._hasComboH = comboH
    self._filePickerLabels = labels[5: 7]

    # Set object's name
    self.setObjectName(name)

    # Optional Datum Shift instead of +towgs84
    self._datumShift = None
    # Optional Geoid Grid to add to +towgs84
    self._geoidGrid = None

    # Height
    heightHLayout = QtGui.QHBoxLayout()
    hLabel = QtGui.QLabel(labels[2])
    hLabel.setToolTip(QCA.translate("hLabelTooltip", "Height"))
    heightHLayout.addWidget(hLabel, alignment=Qt.AlignLeft|Qt.AlignVCenter)
    self.heightWidget = HeightWidget(self, z, ell2Ortho=self._ell2ortho,
      rep=repH)
    heightHLayout.addWidget(self.heightWidget)
    heightHLayout.setContentsMargins(0, 0, 0, 0)

    # phi, lamda
    self._mode = initMode
    if self._mode == self.ModeFile:
     rep = DegreesWidget.DDD
    else:
     rep = self._mode

    self._rep = rep
    self.latWidget = DegreesWidget(self, latitude=True, rep=self._rep)
    self.lonWidget = DegreesWidget(self, latitude=False, rep=self._rep)

    # Easting, Northing
    easting = QCA.translate("easting", "Easting")
    northing = QCA.translate("northing", "Northing")
    self.eWidget = ProjectedWidget(self, name=easting)
    self.nWidget = ProjectedWidget(self, name=northing)

    # File Picker
    self._filePicker = FilePicker(self,
      filt=QCA.translate("FilePicker", "XYZ files (*.xyz);;All Files (*)"))

    # Connect signals
    for w in (self.latWidget, self.lonWidget, self.heightWidget,
      self.eWidget, self.nWidget):
      w.textEditedSignal.connect(self.pointChanged)
    self._filePicker.pathChanged.connect(self.fpChanged)

    # Now build the coordinates widgets
    xx = ((labels[0], labels[3]), (self.latWidget, self.eWidget),
      (QCA.translate("latwidget", "Latitude"), easting))
    yy = ((labels[1], labels[4]), (self.lonWidget, self.nWidget),
      (QCA.translate("lonwidget", "Longitude"), northing))

    self.coords = []
    for coord in (xx, yy):
      sWidget = QtGui.QStackedWidget()
      #sWidget.setContentsMargins(0, 0, 0, 0)
      for label, dw, toolTip in zip(*coord):
        # Build a Label + Degrees widget
        w = QtGui.QWidget()
        # Add a layout for lat, long, height
        hlayout = QtGui.QHBoxLayout()
        hlayout.setContentsMargins(0, 0, 0, 0)
        # The label
        cLabel = QtGui.QLabel(label)
        cLabel.setToolTip(toolTip)
        hlayout.addWidget(cLabel, alignment=Qt.AlignLeft|Qt.AlignVCenter)
        # add the Degrees widget
        hlayout.addWidget(dw)
        w.setLayout(hlayout)
        # add it to the stackedWidget
        sWidget.addWidget(w)

      # save it into self.coords
      self.coords.append(sWidget)

    # The file picker: Build a Label + FilePicker widget
    hlayout = QtGui.QHBoxLayout()
    hlayout.setContentsMargins(0, 0, 0, 0)
    # The label
    hlayout.addWidget(QtGui.QLabel(), alignment=Qt.AlignLeft|Qt.AlignVCenter)
    hlayout.addWidget(self._filePicker)
    self.pickerWithLabel = QtGui.QWidget()
    self.pickerWithLabel.setLayout(hlayout)

    # Projection button
    #self.projBtn = QtGui.QPushButton()
    self.projBtn = TinyButton(u"\N{DOWNWARDS DOUBLE ARROW}", self)
    self.projBtn.clicked.connect(self._selectProj)
    # Button is transparent
    self.projBtn.setAutoFillBackground(False)
    #self.projBtn.setStyleSheet("background-color: rgba(255, 255, 255, 0);")
    self.projBtn.setSizePolicy(QtGui.QSizePolicy.Minimum,
      QtGui.QSizePolicy.Expanding)
    self.projBtn.setToolTip(QCA.translate("datum tooltip",
      "Change current Datum / Projection"))

    # a TextEdit to display the PROJ.4 string
    self.projLabel = QtGui.QTextEdit(proj)
    self.projLabel.setReadOnly(True)
    fm = self.projLabel.fontMetrics()
    rowHeight = fm.lineSpacing()
    self.projLabel.setFixedHeight(2.6 * rowHeight)
    self.projLabel.setStyleSheet("Text-align:left")
    self.projLabel.setStyleSheet("background-color: rgba(255, 255, 255, 160);")
    self.projLabel.setTextInteractionFlags(Qt.TextBrowserInteraction)
    self.projLabel.setToolTip(
      QCA.translate("projTooltip",
      "This is the current Datum / Projection PROJ.4 string"))

    # Point Widget
    xyzWidget = QtGui.QWidget()
    xyzLayout = QtGui.QHBoxLayout()
    xyzLayout.setContentsMargins(0, 0, 0, 0)
    xyzLayout.addWidget(self.coords[0], alignment=Qt.AlignLeft)
    xyzLayout.addWidget(self.coords[1], alignment=Qt.AlignLeft)
    xyzLayout.addLayout(heightHLayout)
    xyzWidget.setLayout(xyzLayout)

    # The pointOrFileWidget 
    self.pointOrFileWidget = QtGui.QStackedWidget()
    self.pointOrFileWidget.addWidget(xyzWidget)
    self.pointOrFileWidget.addWidget(self.pickerWithLabel)

    inputLayout = QtGui.QHBoxLayout()
    inputLayout.addWidget(self.pointOrFileWidget)

    combosLayout = QtGui.QVBoxLayout()
    combosLayout.setContentsMargins(0, 0, 0, 0)

    # Stacked Widget for plane/geographic representation
    self.formatStackedWidget = QtGui.QStackedWidget()

    # Create "Plane" combo
    self.planeCombo = QtGui.QComboBox()
    self.planeCombo.setObjectName("planeCombo")

    # Create "Geographic" combo
    self.geographicCombo = QtGui.QComboBox()
    self.geographicCombo.setObjectName("geographicCombo")

    if self._hasComboU and self._hasComboU.upper().startswith('FILE'):
      enableFile = True
    else:
      enableFile = False

    self.formatStackedWidget.addWidget(self.planeCombo)
    self.formatStackedWidget.addWidget(self.geographicCombo)
    combosLayout.addWidget(self.formatStackedWidget,
      stretch=0, alignment=Qt.AlignLeft)

    # Optional combo box for Height representation
    formats = (QCA.translate("hcombo", "ell"), QCA.translate("hcombo", "ortho"))
    self.heightCombo = QtGui.QComboBox()
    self.heightCombo.setToolTip(QCA.translate("hcombo",
      "Change height representation among\n"
      "ellipsoidical and orthometric height in meters"))
    self.heightCombo.addItems(formats)
    combosLayout.addWidget(self.heightCombo, alignment=Qt.AlignLeft)


    # Connect Signals
    self.heightCombo.currentIndexChanged.connect(self.setHRep)
    self.planeCombo.currentIndexChanged.connect(self._indexChanged)
    self.geographicCombo.currentIndexChanged.connect(self._indexChanged)
    self.enableFileMode(enableFile)

    inputLayout.addLayout(combosLayout, stretch=1)

    # Set Projection
    self.setProj(proj)

    # Build widget layout:
    v = QtGui.QVBoxLayout()
    coordGroup = QtGui.QGroupBox(QCA.translate("datumGroup",
      "Datum and Projection:"))
    g = QtGui.QHBoxLayout()
    coordGroup.setFlat(True)
    #g.addWidget(self.projLabel, alignment=Qt.AlignTop, stretch=1)
    g.addWidget(self.projLabel, alignment=Qt.AlignTop)
    #g.addWidget(self.projBtn, alignment=Qt.AlignLeft|Qt.AlignVCenter)
    g.addWidget(self.projBtn, alignment=Qt.AlignLeft|Qt.AlignTop)
    v.addLayout(g, stretch=1)
    v.addLayout(inputLayout)
    coordGroup.setLayout(v)
    f = coordGroup.font()
    f.setBold(True)
    coordGroup.setFont(f)

    # Main layout:
    mainLayout = QtGui.QVBoxLayout()
    mainLayout.addWidget(coordGroup)
    self.setLayout(mainLayout)

    if not self._hasComboU:
      self.formatStackedWidget.hide()
    if not (self._hasComboH and self._ell2ortho):
      self.heightCombo.hide()

    # Default is InputMode
    self.setFilePickerMode(FilePicker.InputMode)

    if self._mode == self.ModeFile:
      # Show the File Picker
      self.showFilePicker(True)

    # Set Combo Boxes
    #self.planeCombo.setCurrentIndex(self.ModeD)
    #self.geographicCombo.setCurrentIndex(self._rep)
    self.setValue(x, y, z)

  def filePath(self):
    """ Return the File Picker text content

      :returns: File Picker text content
      :rtype: string, unicode
      :raises:
    """
    layout, label, filePicker = self.pickerWithLabel.children()
    return filePicker.text()

  def filePickerMode(self):
    """ Return the File Picker mode

      :returns: File Picker mode
      :rtype: int
      :raises:
    """
    layout, label, filePicker = self.pickerWithLabel.children()
    return self._filePickerLabels.index(label.text())

  def enableFileMode(self, enable):
    """ Enable / disable `self.ModeFile` in combo box

      :param enable: enable / disable file mode
      :type enable: bool
      :raises:
    """
    # Disconnect signals
    self.planeCombo.currentIndexChanged.disconnect(self._indexChanged)
    self.geographicCombo.currentIndexChanged.disconnect(self._indexChanged)
    self.planeCombo.clear()
    self.geographicCombo.clear()
    planeItems = (QCA.translate("plane", "M.MM"), )
    planeToolTip = QCA.translate("plane", "Easting, Northing in meters")
    geographicItems = (QCA.translate("degs", "D.DD"),
      QCA.translate("degs", "D M.MM"), QCA.translate("degs", "D M S.SS"))
    geographicToolTip = (QCA.translate("degs",
      "Change angular representation among\n"
      "degrees.decimals,\ndegrees, minutes.decimals\nand degrees, "
      "minutes, seconds.decimals"))

    if enable:
      extraItem = (QCA.translate("file", "File"), )
      extraToolTip = QCA.translate("file",
        "\nOr select File for file conversion")
      planeItems += extraItem
      planeToolTip += extraToolTip
      geographicItems += extraItem
      geographicToolTip += extraToolTip

    self.planeCombo.addItems(planeItems)
    self.planeCombo.setToolTip(planeToolTip)
    self.geographicCombo.addItems(geographicItems)
    self.geographicCombo.setToolTip(geographicToolTip)

    # Reset current index
    self.planeCombo.setCurrentIndex(self.ModeD)
    self.geographicCombo.setCurrentIndex(self._rep)

    # Reconnect signals
    self.planeCombo.currentIndexChanged.connect(self._indexChanged)
    self.geographicCombo.currentIndexChanged.connect(self._indexChanged)

  def setFilePickerMode(self, mode):
    """ Set the File Picker mode

      :param mode: set File Picker mode to `mode`
      :type mode: int
      :raises:
    """
    layout, label, filePicker = self.pickerWithLabel.children()
    label.setText(self._filePickerLabels[mode])
    label.setToolTip(self._filePickerLabels[mode])
    filePicker.setMode(mode)

  def pointChanged(self, newValue):
    """ Emit a `changedSignal` Signal with 'point' argument.

        newValue argument is discarded.

      :param newValue: argument is discarded
      :type newValue: string
      :raises:
    """
    self.changedSignal.emit('point')

  def fpChanged(self, newPath):
    """ Emit a `fileChangedSignal` Signal with `newPath` argument.

      :param newPath: new file path
      :type newPath: string, unicode
      :raises:
    """
    if newPath:
      self.fileChangedSignal.emit(newPath)

  def datumShift(self):
    """ Return Datum Shift for this point

      :returns: Datum Shift for this point
      :rtype: float
      :raises:
    """
    return self._datumShift

  def geoidGrid(self):
    """ Return Geoid Grid for this point

      :returns: Geoid Grid for this point
      :rtype: float
      :raises:
    """
    return self._geoidGrid

  def setEll2Ortho(self, ell2Ortho):
    """ Set ellipsoidical to orthometric height (geoid) difference

      :param ell2Ortho: ellipsoidical to orthometric height (geoid) difference
      :type ell2Ortho: float or None
      :raises:
    """
    self._ell2ortho = ell2Ortho
    self.heightWidget.setEll2Ortho(ell2Ortho)
    if self._ell2ortho is None:
      self.heightCombo.hide()
    else:
      self.heightCombo.show()

  def setValue(self, *values):
    """ Set Latitude, Longitude, Height [ell2Ortho] **OR**
        Easting, Northing, Height [ell2Ortho]

      :param \*values: Latitude, Longitude, Height [ell2Ortho]
      :type \*values: float
      :raises:
    """
    if self.isLatLon():
      for w, j in zip((self.lonWidget, self.latWidget), xrange(3)):
        if hasattr(values[j], '__iter__'):
          w.setValue(*values[j])
        else:
          w.setValue(values[j])
    else:
      self.eWidget.setValue(values[0])
      self.nWidget.setValue(values[1])

    self.heightWidget.setEllH(values[2])

  def isFilePickerShown(self):
    """ Return True if the File Picker is shown

      :returns: True if the File Picker is shown
      :rtype: bool
      :raises:
    """
    if self.pointOrFileWidget.currentIndex == self.FileIndex:
      return True
    else:
      return False

  def showFilePicker(self, showIt):
    """ If `showIt` evaluates True set widget mode to show the File Picker,
        else show coordinates widget

      :param showIt: set widget mode to show the File Picker if True
      :type showIt: bool
      :raises:
    """
    if showIt:
      self.pointOrFileWidget.setCurrentIndex(self.FileIndex)
    else:
      self.pointOrFileWidget.setCurrentIndex(self.PointIndex)

  def _indexChanged(self, index):
    """ Index changed in the combo boxes: set appropriate representation

      :param index: new index in the ComboBox
      :type index: int
      :raises:
    """
    if index < 0:
      return

    rep = None
    if self.sender() == self.planeCombo:
      if index == 1:
        self.changedSignal.emit('File On')
      else:
        rep = index
        self.changedSignal.emit('File Off')
    elif self.sender() == self.geographicCombo:
      if index == self.ModeFile:
        self.changedSignal.emit('File On')
      else:
        rep = index
        self.changedSignal.emit('File Off')
    else:
      raise SystemExit("FATAL ERROR..... _indexChanged: Invalid sender %s!" %
        self.sender().objectName())

    if rep is not None:
      self.setDRep(rep)

  def setDRep(self, rep):
    """ Set Degrees representation to rep if :attr:`isLatLon()` evaluates to
        True, else...

      :param rep: representation to use for latLon or plane coordinates
      :type rep: :class:`ModeD` .. :class:`ModeDMS`
      :raises:
    """
    if self.isLatLon():
      self.latWidget.setRep(rep)
      self.lonWidget.setRep(rep)
    self._rep = rep

  def setHRep(self, rep):
    """ Set Height representation to rep

      :param rep: representation to use for height
      :type rep: :class:`RepEll` .. :class:`RepOrtho`
      :raises:
    """
    self.heightWidget.setRep(rep)

  def tvalue(self):
    """ Return widget value as tuples of text

      :returns: widget value as tuples of text
      :rtype: tuple
      :raises:
    """
    if self.isLatLon():
      return [self.latWidget.tvalue(), self.lonWidget.tvalue(),
        (str(self.heightWidget.ellH()), str(self.heightWidget.ell2Ortho()))]
    else:
      return [self.eWidget.tvalue(), self.nWidget.tvalue(),
        (str(self.heightWidget.ellH()), str(self.heightWidget.ell2Ortho()))]

  def fvalue(self):
    """ Return widget value as tuples of float

      :returns: widget value as tuples of float
      :rtype: tuple
      :raises:
    """
    if self.isLatLon():
      return [self.latWidget.fvalue(), self.lonWidget.fvalue(),
        (self.heightWidget.ellH(), self.heightWidget.ell2Ortho())]
    else:
      return [self.eWidget.fvalue(), self.nWidget.fvalue(),
        (self.heightWidget.ellH(), self.heightWidget.ell2Ortho())]

  def svalue(self):
    """ Return widget value as tuple of strings

      :returns: widget value as tuples of strings
      :rtype: tuple
      :raises:
    """
    if self.isLatLon():
      return [self.latWidget.svalue(), self.lonWidget.svalue(),
        (str(self.heightWidget.ellH()), str(self.heightWidget.ell2Ortho()))]
    else:
      return [self.eWidget.svalue(), self.nWidget.svalue(),
        (str(self.heightWidget.ellH()), str(self.heightWidget.ell2Ortho()))]

  def xyz(self):
    """ Return either

          * longitude, latitude, height
          * easting, northing, height

        according to :class:`isLatLon()`

      :returns: x, y, z
      :rtype: tuple
      :raises:

     .. note:: Height is always **ELLIPSOIDICAL**.
    """
    if self.isLatLon():
      return [self.lonWidget.fvalue(0)[0], self.latWidget.fvalue(0)[0],
        self.heightWidget.ellH()]
    else:
      return [self.eWidget.fvalue(0)[0], self.nWidget.fvalue(0)[0],
        self.heightWidget.ellH()]

  def _selectProj(self):
    """ Open a dialog to select datum and projection
    """
    dlg = ProjDialog(self.projStr(), self)
    dlg.resize(640, 480)
    if dlg.exec_():
      projStr = dlg.projection()
      if self.setProj(projStr):
        self.changedSignal.emit('proj')
        self.adjustSize()

  def ell2Ortho(self):
    """ Return ellipsoidical to orthometric height difference

      :returns: ellipsoidical to orthometric height difference
      :rtype: float or None
      :raises:
    """
    return self.heightWidget.ell2Ortho()

  def isLatLon(self):
    """ Return True if projection is in geographic coordinates

      :returns: True if projection is in geographic coordinates
      :rtype: bool
      :raises:
    """
    return self._proj.is_latlong()

  def proj(self):
    """ Return proj object for this point

      :returns: proj object for this point
      :rtype: pyproj instance
      :raises:
    """
    return self._proj

  def projStr(self):
    """ Return proj srs string for this point

      :returns: proj srs string for this point
      :rtype: string
      :raises:
    """
    version = __version__.split('.')
    if version < (1, 9, 0):
      return self._proj.srs.replace('+units=m ', '')
    else:
      return self._proj.srs

  def projString(self):
    """ Return full proj string (with geoidgrids and datumShifts)

      :returns: proj string (with geoidgrids and datumShifts)
      :rtype: string
      :raises:
    """
    return self._projString

  def setProj(self, projS):
    """ Set projection for this point and return it if ok else False

      :param projS: PROJ.4 string defining Datum / Projection
      :type projS: string
      :returns: projection for this point or False
      :rtype: string or False
      :raises:
    """
    self._projString = projS
    retval = False
    self._datumShift = None
    self._geoidGrid = None
    cleanProjS = projS

    # Search for extra keyword(s)
    for extraKeyword in EXTRA_KEYWORDS:
      b, key, e = projS.partition(extraKeyword)
      if key == DATUMSHIFT_KEYWORD:
        # extra keyword found, parse its value
        pn = e.split()[0]
        try:
          self._datumShift = DatumShift(pn)
        except IOError, e:
          msgBox = QtGui.QMessageBox(QtGui.QMessageBox.Warning,
            QCA.translate("datumMbox", 'IO Error'),
            QCA.translate("datumMbox",
            "Cannot load datum shift file '%s'.\nThe reason is:\n%s.") %
            (pn, e), QtGui.QMessageBox.Ok)
          msgBox.exec_()
          return retval
        else:
          if self._datumShift.datumShift() == (None, None):
            self._datumShift = None
            msgBox = QtGui.QMessageBox(QtGui.QMessageBox.Warning,
              QCA.translate("datumMbox", 'Datum Shift Error'),
              QCA.translate("datumMbox",
                "'%s' is not a valid Datum Shift file.") % (pn),
              QtGui.QMessageBox.Ok)
            msgBox.exec_()
            return retval
          # Remove extra from the string
          cleanProjS = cleanProjS.replace(extraKeyword + pn, '')
      elif key == GEOIDGRIDS_KEYWORD:
        # extra keyword found, parse its value
        pn = e.split()[0]
        try:
          self._geoidGrid = Geoid(pn)
        except IOError, e:
          msgBox = QtGui.QMessageBox(QtGui.QMessageBox.Warning,
            QCA.translate("geoidMbox", 'IO Error'),
            QCA.translate("geoidMbox",
            "Cannot load geoid grid file '%s'.\nThe reason is:\n%s.") %
            (pn, e), QtGui.QMessageBox.Ok)
          msgBox.exec_()
          return retval
        else:
          if self._geoidGrid.geoid() == None:
            self._geoidGrid = None
            msgBox = QtGui.QMessageBox(QtGui.QMessageBox.Warning,
              QCA.translate("geoidMbox", 'Geoid Grid Error'),
              QCA.translate("geoidMbox",
              "'%s' is not a valid Geoid Grid file.") % (pn),
              QtGui.QMessageBox.Ok)
            msgBox.exec_()
            return retval
          # Remove extra from the string
          cleanProjS = cleanProjS.replace(extraKeyword + pn, '')

    try:
      self._proj = Proj(cleanProjS, preserve_units=True)
    except RuntimeError, e:
      msgBox = QtGui.QMessageBox(QtGui.QMessageBox.Warning,
        QCA.translate("projMbox", 'Invalid PROJ.4 string'),
        QCA.translate("projMbox",
        "'%s' is an invalid PROJ.4 string.\nThe reason is:\n%s.") %
        (projS, e), QtGui.QMessageBox.Ok)
      msgBox.exec_()
    else:
      if self._proj.is_latlong():
        index = 0
      else:
        index = 1
      self.coords[0].setCurrentIndex(index)
      self.coords[1].setCurrentIndex(index)
      self.projLabel.setText(projS)
      retval = self._proj

    if self.isLatLon():
      self.formatStackedWidget.setCurrentIndex(self.GeographicIndex)
    else:
      self.formatStackedWidget.setCurrentIndex(self.PlaneIndex)
    return retval

  def decimals(self):
    """ Return x, y, z decimals for representation as tuples

      :returns: decimals for representation of x, y, z
      :rtype: tuple (of  tuples)
      :raises:
    """
    if self.isLatLon():
      rep = self.geographicCombo.currentIndex()
      if rep == DegreesWidget.DDD:
        xdecimals = (self.lonWidget.ddecimals, )
        ydecimals = (self.latWidget.ddecimals, )
      elif rep == DegreesWidget.DMM:
        xdecimals = (0, self.lonWidget.mdecimals)
        ydecimals = (0, self.latWidget.mdecimals)
      elif rep == DegreesWidget.DMS:
        xdecimals = (0, 0, self.lonWidget.sdecimals)
        ydecimals = (0, 0, self.latWidget.sdecimals)
    else:
      xdecimals = self.eWidget.decimals
      ydecimals = self.nWidget.decimals
    zdecimals = self.heightWidget.decimals
    return xdecimals, ydecimals, zdecimals

  def coordFormat(self):
    """ Return format of coordinates as shown in the comboBox
    """

    if self.isLatLon():
      combo = self.geographicCombo
    else:
      combo = self.planeCombo
    index = combo.currentIndex()
    allItems = [combo.itemText(i) for i in range(combo.count())]
    return allItems[index]

if __name__ == '__main__':
  from signal import signal, SIGINT, SIG_DFL

  signal(SIGINT, SIG_DFL)
  app = QtGui.QApplication(sys.argv)
  # LatLong
  x = (13., 45.81882)
  y = (45.710551,)
  z = 285.8
  w1 = CoordWidget((x, y, z), comboU='File',)
  # Plane
  x = 4000000
  y = 50000000
  z = 285.8
  w2 = CoordWidget((x, y, z), comboU='File',
    proj='+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +no_defs',)
    #mode=CoordWidget.FileMode,
    #projTo="+proj=longlat +ellps=intl +pm=rome +no_defs",
    #projTo="+init=epsg:3004 +towgs84=-122.74,-34.27,-22.83,"
    #"-1.884,-3.400,-3.030,-15.62",
    #ell2Ortho=None, name="Molo Sartorio",)
    #dmsChars=['', '', ''])
  #dialog.selectFields("/home/vidmar/Geod/qt/Molo_Sartorio_UTM33.xyz", False,
  #  None, "filippo")
  w1.show()
  w2.show()
  sys.exit(app.exec_())
